

const int VOLT_IN_ONE   = 0;
const int VOLT_IN_TWO   = 1;
const int VOLT_IN_THREE = 2;

const float MIN_BATTERY_VOLTAGE = 12;
const float MAX_BATTERY_VOLTAGE = 13.7;

const int CHARGE_ENABLE_PIN = 12;



const float RES_14VOLT_R1 = 4590;
const float RES_14VOLT_R2 = 2250;

const float RES_6VOLT_R1  = 990;
const float RES_6VOLT_R2  = 2460;

const float RES_6VOLT_R11 = 990;
const float RES_6VOLT_R12 = 2220;

const int BAUD_RATE = 19200;
const int SAMPLE_THRESHOLD = 15;

char prev = 'y';

enum LatchType
{
 Latch_Auto,
 Latch_Never,
 Latch_Always
};

LatchType latchType = Latch_Auto;
float prevOne = 0.0;
float stableBatteryVoltage = 0.0;
int numSamples = 0;



float calculateVoltage( int pinNum, float rOne, float rTwo )
{
  int adcVal = analogRead( pinNum );
  float vOut = ( adcVal * 5.0 ) / 1024.0;
  return vOut / ( rTwo/ ( rOne + rTwo ));
}


void setup()
{
  pinMode( VOLT_IN_ONE, INPUT );
  pinMode( VOLT_IN_TWO, INPUT );
  pinMode( VOLT_IN_THREE, INPUT );  

  pinMode( CHARGE_ENABLE_PIN, OUTPUT );
  Serial.begin( BAUD_RATE );
}


void handleCommands()
{
 if( Serial.available() ) {
  char cmd = Serial.read();
  if( cmd == 'a' ) {
    Serial.print( "a#" );
    Serial.println( stableBatteryVoltage );
  }
  else if( cmd == 'b' ) {  
    Serial.print( "b#" );  
    Serial.println( calculateVoltage( VOLT_IN_TWO, 
                                      RES_6VOLT_R1, 
                                      RES_6VOLT_R2 ));
  }
  else if( cmd == 'c' ) {
    Serial.print( "c#" );
    Serial.println( calculateVoltage( VOLT_IN_THREE, 
                                      RES_6VOLT_R11, 
                                      RES_6VOLT_R12 ));
  }
  else if( cmd == 'd' ) {
    if( latchType == Latch_Auto ) {
      if( stableBatteryVoltage < MIN_BATTERY_VOLTAGE ) {
        prev = 'y';
        Serial.println( "d#y" );
      }
      else if( stableBatteryVoltage > MAX_BATTERY_VOLTAGE ) {
        prev = 'n';
        Serial.println( "d#n" );
      }
      else {
        Serial.print( "d#" );
        Serial.write( prev );
        Serial.println( "" );
      }
    }
    else if( latchType == Latch_Always ) {
      Serial.println( "d#y" );
    }
    else {
      Serial.println( "d#n" ); 
    }
  }
  else if( cmd == 'u' ) {
    latchType = Latch_Auto; 
  }
  else if( cmd == 'y' ) {
    latchType = Latch_Always;
  }
  else if( cmd == 'n' ) {
    latchType = Latch_Never;
  }
  else if( cmd == 'l' ) {
    const char *resp = latchType == Latch_Auto ? "l#u" :
                           latchType == Latch_Always ? "l#y" : "l#n";
    Serial.println( resp );
  }
  else if( cmd == '0' ) {
    Serial.println( "*" ); 
  }
  }
}



void loop()
{
  
  float batteryOutput = calculateVoltage( VOLT_IN_ONE, 
                                          RES_14VOLT_R1, 
                                          RES_14VOLT_R2 );
  
  if( prevOne == 0.0 ) {
    prevOne == batteryOutput;
  }
  else {
     batteryOutput = ( batteryOutput + prevOne ) / 2; 
  }
  if( stableBatteryVoltage == 0.0 ) {
    stableBatteryVoltage = batteryOutput;
  }
  if( numSamples == SAMPLE_THRESHOLD ) {
    stableBatteryVoltage = batteryOutput;
    numSamples = 0;
    prevOne = 0.0;
  }
  ++ numSamples;
  
  //Latch values are reverse since latching means disconnecting from mains
  //due to relay circuit 
  if( latchType == Latch_Auto ) {
    if( stableBatteryVoltage < MIN_BATTERY_VOLTAGE ) {
      digitalWrite( CHARGE_ENABLE_PIN, LOW );
    }
    else if( stableBatteryVoltage > MAX_BATTERY_VOLTAGE ) {
      digitalWrite( CHARGE_ENABLE_PIN, HIGH );
    }
  }
  else if( latchType == Latch_Never ) {
    digitalWrite( CHARGE_ENABLE_PIN, HIGH );
  }
  else if( latchType == Latch_Always ) {
    digitalWrite( CHARGE_ENABLE_PIN, LOW ); 
  }
  handleCommands();
}

